/*
 * EntryClient.java
 *
 * Created on September 11, 2007, 1:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.client;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URI;
import java.util.List;
import java.util.logging.Logger;
import org.infoset.xml.Document;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.XMLWriter;
import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;

/**
 *
 * @author alex
 */
public class EntryClient extends AppClient
{
   Reference location;
   Entry entry;
   Client client;
   
   /** Creates a new instance of EntryClient */
   public EntryClient(Reference location,Identity identity)
   {
      super(identity);
      this.location = location;
      this.entry = null;
      this.client = null;
   }

   public EntryClient(Entry entry) {
      this(null,entry,null);
   }
   public EntryClient(Client client,Entry entry) {
      this(client,entry,null);
   }
   /** Creates a new instance of EntryClient */
   public EntryClient(Client client,Entry entry,Identity identity)
   {
      super(identity);
      this.client = client;
      this.location = null;
      this.entry = entry;
   }

   public void setClient(Client client) {
      this.client = client;
   }
   
   public Reference getLocation() {
      return location;
   }
   
   public Entry getEntry()
   {
      return this.entry;
   }
   
   public void setEntry(Entry entry)
   {
      this.entry = entry;
   }
   
   public Status updateMedia(Representation rep)
   {
      Entry.Media media = entry.getMediaContent();
      if (media==null) {
         return Status.CLIENT_ERROR_NOT_FOUND;
      }
      
      URI mediaURI = media.getLocation();
      if (client==null) {
         client = new Client(new Context(Logger.getLogger(EntryClient.class.getName())),Protocol.valueOf(mediaURI.getScheme()));
         client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      }
      Request request = new Request(Method.PUT,mediaURI.toString());
      if (identity!=null) {
         request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,identity.getName(),identity.getPassword()));
      }
      if (cookie!=null) {
         request.getCookies().add(cookie);
      }
      request.setEntity(rep);
      Response response = client.handle(request);
      if (response.isEntityAvailable()) {
         response.getEntity().release();
      }
      return response.getStatus();
   }
   
   public Status get() 
      throws IOException,XMLException
   {
      if (client==null) {
         client = new Client(new Context(Logger.getLogger(EntryClient.class.getName())),location.getSchemeProtocol());
         client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      }
      Request request = new Request(Method.GET,location);
      if (identity!=null) {
         request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,identity.getName(),identity.getPassword()));
      }
      if (cookie!=null) {
         request.getCookies().add(cookie);
      }
      Response response = client.handle(request);
      if (response.getStatus().isSuccess() && response.isEntityAvailable()) {
         XMLRepresentationParser parser = new XMLRepresentationParser();
         Document doc = parser.load(response.getEntity());
         this.entry = new Entry(doc);
      }
      if (response.isEntityAvailable()) {
         response.getEntity().release();
      }
      return response.getStatus();
   }
   
   public Status exists() 
   {
      if (client==null) {
         client = new Client(new Context(Logger.getLogger(EntryClient.class.getName())),location.getSchemeProtocol());
         client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      }
      Request request = new Request(Method.HEAD,location);
      if (identity!=null) {
         request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,identity.getName(),identity.getPassword()));
      }
      if (cookie!=null) {
         request.getCookies().add(cookie);
      }
      Response response = client.handle(request);
      if (response.isEntityAvailable()) {
         response.getEntity().release();
      }
      return response.getStatus();
   }
   
   public Status delete()
   {
      Reference entryLoc = null;
      if (location==null) {
         List<Link> editLinks = entry.getLinks().get("edit");
         if (editLinks==null || editLinks.size()==0) {
            return Status.CLIENT_ERROR_EXPECTATION_FAILED;
         }
         URI entryURI = editLinks.get(0).getLink();
         entryLoc = new Reference(entryURI.toString());
      } else {
         entryLoc = location;
      }
      if (client==null) {
         client = new Client(new Context(Logger.getLogger(EntryClient.class.getName())),entryLoc.getSchemeProtocol());
         client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      }
      Request request = new Request(Method.DELETE,entryLoc);
      if (identity!=null) {
         request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,identity.getName(),identity.getPassword()));
      }
      if (cookie!=null) {
         request.getCookies().add(cookie);
      }
      Response response = client.handle(request);
      if (response.isEntityAvailable()) {
         response.getEntity().release();
      }
      return response.getStatus();
   }
   
   public Status update()
      throws IOException,XMLException
   {
      return update(entry.getDocument());
   }
   
   public Status update(final Document entryDoc)
      throws IOException,XMLException
   {
      List<Link> editLinks = entry.getLinks().get("edit");
      if (editLinks==null || editLinks.size()==0) {
         return Status.CLIENT_ERROR_EXPECTATION_FAILED;
      }
      URI entryURI = editLinks.get(0).getLink();
      /*
      System.out.println(entryURI.toString());
      System.out.flush();
       */
      
      if (client==null) {
         client = new Client(new Context(Logger.getLogger(EntryClient.class.getName())),Protocol.valueOf(entryURI.getScheme()));
         client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      }
      Request request = new Request(Method.PUT,entryURI.toString());
      if (identity!=null) {
         request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,identity.getName(),identity.getPassword()));
      }
      if (cookie!=null) {
         request.getCookies().add(cookie);
      }
      request.setEntity(new OutputRepresentation(MediaType.APPLICATION_ATOM_XML) {
         public void write(OutputStream os) 
            throws IOException
         {
            Writer w = new OutputStreamWriter(os,"UTF-8");
            try {
               XMLWriter.writeDocument(entryDoc,w);
            } catch (XMLException ex) {
               throw new IOException(ex.getMessage());
            }
         }
      });
      Response response = client.handle(request);
      Status status = response.getStatus();
      boolean hasEntity = false;
      try {
         hasEntity = response.isEntityAvailable();
         if (status.isSuccess() && hasEntity) {
            XMLRepresentationParser parser = new XMLRepresentationParser();
            Document doc = parser.load(response.getEntity());
            this.entry = new Entry(doc);
         }
      } finally {
         if (hasEntity) {
            response.getEntity().release();
         }
      }
      return status;
   }
   
}
